package cn.tedu.jsd2207csmallpassport.service.impl;

import cn.tedu.jsd2207csmallpassport.ex.ServiceException;
import cn.tedu.jsd2207csmallpassport.mapper.AdminMapper;
import cn.tedu.jsd2207csmallpassport.mapper.AdminRoleMapper;
import cn.tedu.jsd2207csmallpassport.pojo.dto.AdminAddNewDTO;
import cn.tedu.jsd2207csmallpassport.pojo.dto.AdminLoginDTO;
import cn.tedu.jsd2207csmallpassport.pojo.entity.Admin;
import cn.tedu.jsd2207csmallpassport.pojo.entity.AdminRole;
import cn.tedu.jsd2207csmallpassport.pojo.vo.AdminListItemVO;
import cn.tedu.jsd2207csmallpassport.pojo.vo.AdminStandardVO;
import cn.tedu.jsd2207csmallpassport.security.AdminDetails;
import cn.tedu.jsd2207csmallpassport.service.IAdminService;
import cn.tedu.jsd2207csmallpassport.web.ServiceCode;
import com.alibaba.fastjson.JSON;
import io.jsonwebtoken.Jwts;
import io.jsonwebtoken.SignatureAlgorithm;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.BeanUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.security.authentication.AuthenticationManager;
import org.springframework.security.authentication.UsernamePasswordAuthenticationToken;
import org.springframework.security.core.Authentication;
import org.springframework.security.core.GrantedAuthority;
import org.springframework.security.core.context.SecurityContextHolder;
import org.springframework.security.core.userdetails.User;
import org.springframework.stereotype.Service;

import java.time.LocalDateTime;
import java.util.*;

@Slf4j
@Service
public class AdminServiceImpl implements IAdminService {

    @Value("${csmall.jwt.secret-key}")
    private String secretKey;

    @Value("${csmall.jwt.duration-in-minute}")
    private Long DurationInMinute;

    @Autowired
    AdminMapper adminMapper;
    @Autowired
    private AdminRoleMapper adminRoleMapper;
    @Autowired
    private AuthenticationManager authenticationManager;
    @Override
    public String login(AdminLoginDTO adminLoginDTO) {
        log.info("开始处理【管理员登录】的业务，参数：{}", adminLoginDTO);
        // 执行认证
        Authentication authentication
                = new UsernamePasswordAuthenticationToken(
                adminLoginDTO.getUsername(), adminLoginDTO.getPassword());
        Authentication authenticateResult
                = authenticationManager.authenticate(authentication);
        log.info("认证通过，认证管理器返回：{}", authenticateResult);

        // 从认证结果中获取所需的数据，将用于生成JWT
        Object principal = authenticateResult.getPrincipal();
        log.info("认证结果中的当事人类型：{}", principal.getClass().getName());
        AdminDetails adminDetails = (AdminDetails) principal;
        String username = adminDetails.getUsername();
        Long id =adminDetails.getId();
        Collection<GrantedAuthority> authorities = adminDetails.getAuthorities();
        String authoritiesJsonString = JSON.toJSONString(authorities);

        // 生成JWT数据时，需要填充装到JWT中的数据
        Map<String, Object> claims = new HashMap<>();
        // claims.put("id", 9527);
        claims.put("id",id);
        claims.put("username", username);
        claims.put("authoritiesJsonString", authoritiesJsonString);
        log.info("向JWT中存入id：{}", id);
        log.info("向JWT中存入username：{}", username);
        log.info("向JWT中存入authoritiesJsonString：{}", authoritiesJsonString);
        // 以下是生成JWT的固定代码

        Date date = new Date(System.currentTimeMillis() + DurationInMinute* 60 * 1000L);
        String jwt = Jwts.builder()
                // Header
                .setHeaderParam("alg", "HS256")
                .setHeaderParam("typ", "JWT")
                // Payload
                .setClaims(claims)
                // Signature
                .setExpiration(date)
                .signWith(SignatureAlgorithm.HS256, secretKey)
                .compact();
        log.debug("生成的JWT：{}", jwt);
        return jwt;
    }

    @Override
    public void addNew(AdminAddNewDTO adminAddNewDTO) {

        log.info("开始处理【添加管理员】的业务,参数:{}",adminAddNewDTO);
        {
            log.info("即将检查用户名是否被占用……");
            String username = adminAddNewDTO.getUsername();
            int count = adminMapper.countByUsername(username);
            if (count != 0) {
                // 是：，抛出异常
                String message = "添加管理员失败，用户名【" + username + "】已经被占用！";
                log.info(message);
                throw new ServiceException(ServiceCode.ERR_CONFLICT, message);
            }
        }
        {
            log.info("即将检查手机号码是否被占用……");
            String phone = adminAddNewDTO.getPhone();
            int count = adminMapper.countByPhone(phone);
            if (count != 0) {
                // 是：，抛出异常
                String message = "添加管理员失败，手机号【" + phone + "】已经被占用！";
                log.info(message);
                throw new ServiceException(ServiceCode.ERR_CONFLICT, message);
            }
        }
        {
            log.info("即将检查email是否被占用……");
            String email = adminAddNewDTO.getEmail();
            int count = adminMapper.countByPhone(email);
            if (count != 0) {
                // 是：，抛出异常
                String message = "添加管理员失败，手机号【" + email + "】已经被占用！";
                log.info(message);
                throw new ServiceException(ServiceCode.ERR_CONFLICT, message);
            }
        }

        Admin admin =new Admin();
        BeanUtils.copyProperties(adminAddNewDTO,admin);
        admin.setLoginCount(0);
        log.info("即将插入管理员数据，参数：{}", admin);
        int rows =adminMapper.insert(admin);
        if (rows != 1) {
            String message = "添加管理员失败，服务器忙，请稍后再次尝试！";
            log.info(message);
            throw new ServiceException(ServiceCode.ERR_INSERT, message);
        }
        // 插入管理员与角色关联的数据
        Long[] roleIds = adminAddNewDTO.getRoleIds();
        AdminRole[] adminRoles = new AdminRole[roleIds.length];
        LocalDateTime now = LocalDateTime.now();
        for (int i = 0; i < roleIds.length; i++) {
            AdminRole adminRole = new AdminRole();
            adminRole.setAdminId(admin.getId());
            adminRole.setRoleId(roleIds[i]);
            adminRole.setGmtCreate(now);
            adminRole.setGmtModified(now);
            adminRoles[i] = adminRole;
        }
        rows = adminRoleMapper.insertBatch(adminRoles);
        if (rows != roleIds.length) {
            String message = "添加管理员失败，服务器忙，请稍后再次尝试！";
            log.warn(message);
            throw new ServiceException(ServiceCode.ERR_INSERT, message);
        }

    }

    @Override
    public List<AdminListItemVO> list() {
        log.info("开始处理[查询管理员列表]的业务,无参数");
        List<AdminListItemVO> list =adminMapper.list();
        Iterator<AdminListItemVO> iterator = list.iterator();
        while (iterator.hasNext()){
            AdminListItemVO item =iterator.next();
            if (item.getId() ==1){
                iterator.remove();
                break;
            }
        }
        return list;
    }

    @Override
    public void delete(Long id) {
        log.debug("开始处理【根据id删除管理员】的业务，参数：{}", id);
        if (id == 1|| id==7){
            String message ="删除管理员失败,该用户为超级管理员";
            log.info(message);
            throw new ServiceException(ServiceCode.ERR_NOT_FOUND, message);
        }
        AdminStandardVO queryResult = adminMapper.getStandardById(id);
        if (queryResult==null){
            String message ="删除管理员失败,尝试访问的数据不存在";
            log.info(message);
            throw new ServiceException(ServiceCode.ERR_NOT_FOUND, message);
        }
        log.info("即将删除:参数{}", id);
        int rows = adminMapper.deleteById(id);
        // 判断返回的行数是否不为1
        if (rows != 1) {
            // 是：抛出异常（ERR_DELETE：服务器忙）
            String message = "删除管理员失败，服务器忙，请稍后再尝试！";
            log.debug(message);
            throw new ServiceException(ServiceCode.ERR_DELETE, message);
        }
        // 删除管理员与角色的关联数据
        rows = adminRoleMapper.deleteByAdminId(id);
        if (rows < 1) {
            // 是：抛出异常（ERR_DELETE：服务器忙）
            String message = "删除管理员失败，服务器忙，请稍后再尝试！";
            log.debug(message);
            throw new ServiceException(ServiceCode.ERR_DELETE, message);
        }
    }

    @Override
    public void setEnable(Long id) {
        updateEnableById(id, 1);
    }

    @Override
    public void setDisable(Long id) {
        updateEnableById(id, 0);
    }



    private void updateEnableById(Long id, Integer enable) {
        String[] s={"禁用","启用"};
        //判断id是否为1
        if (id==1){
            String message = s[enable] + "管理员失败，尝试访问的数据不存在！";
            log.info(message);
            throw new ServiceException(ServiceCode.ERR_NOT_FOUND,message);
        }
        // 检查尝试访问的数据是否存在
        AdminStandardVO adminStandardVO =adminMapper.getStandardById(id);
        if (adminStandardVO==null){
            String message = s[enable] + "管理员失败，尝试访问的数据不存在！";
            throw new ServiceException(ServiceCode.ERR_NOT_FOUND,message);
        }
        // 判断状态是否冲突（当前已经是目标状态）
        if (adminStandardVO.getEnable()==enable){
            String message = s[enable] + "管理员失败，管理员账号已经处于" + s[enable] + "状态！";
            log.info(message);
            throw new ServiceException(ServiceCode.ERR_CONFLICT,message);
        }
        // 准备执行更新
        Admin admin =new Admin();
        admin.setId(id);
        admin.setEnable(enable);
        int rows =adminMapper.update(admin);
        if (rows!=1){
            String message = s[enable] + "管理员失败，服务器忙，请稍后再次尝试！";
            throw new ServiceException(ServiceCode.ERR_UPDATE,message);
        }
    }

}

